package me.chenjp.tracker.core.advice;

import lombok.extern.slf4j.Slf4j;
import me.chenjp.tracker.core.bean.State;
import me.chenjp.tracker.core.exception.AuthenticationException;
import me.chenjp.tracker.core.exception.BaseServiceException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.sql.SQLException;

/**
 * @author: Chenjp
 * @description: 这个人很懒, 没有留下任何注释
 * @create: 2019-05-03 12:55
 */
@Slf4j
@ControllerAdvice
public class ExceptionAdvice {

    @ExceptionHandler({Exception.class})
    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public State exceptionHandler(Exception ex) {
        log.error("Exception:{}", ex);
        return new State(HttpStatus.INTERNAL_SERVER_ERROR.value() * 10, ex.getMessage());
    }

    @ExceptionHandler({AuthenticationException.class})
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public State handleAuthenticationException(AuthenticationException ex) {
        log.error("AuthenticationException:{}", ex);
        return new State(HttpStatus.UNAUTHORIZED.value() * 10, ex.getMessage());
    }

    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public State handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.error("MethodArgumentNotValidException:{}", ex);
        return State.buildFromBindingResult(ex.getBindingResult());
    }

    @ExceptionHandler({ServletRequestBindingException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public State handleServletRequestBindingException(ServletRequestBindingException ex) {
        log.error("MethodArgumentNotValidException:{}", ex);
        return new State(HttpStatus.BAD_REQUEST.value() * 10, ex.getMessage());
    }

    @ExceptionHandler({NoHandlerFoundException.class})
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ResponseBody
    public State handlerNotFoundException(HttpServletRequest req, NoHandlerFoundException ex) {
        log.error("NoHandlerFoundException:{}", ex);
        String errorURL = req.getRequestURL().toString();
        return new State(HttpStatus.NOT_FOUND.value() * 10, "Not found this url:".concat(errorURL));
    }

    @ExceptionHandler({BaseServiceException.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public State handlerBaseServiceException(BaseServiceException ex) {
        log.error("BaseServiceException:{}", ex);
        return ex.getState();
    }

    @ExceptionHandler({ConstraintViolationException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public State handleConstraintViolationException(ConstraintViolationException ex) {
        log.error("ConstraintViolationException:{}", ex);
        return new State(HttpStatus.BAD_REQUEST.value() * 10, ex.getMessage());
    }

    @ExceptionHandler({SQLException.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public State handleSqlException(SQLException ex) {
        log.error("SQLException:{}", ex);
        return new State(HttpStatus.INTERNAL_SERVER_ERROR.value() * 10, "SQL Exception");
    }

    @ExceptionHandler({RuntimeException.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public State handleRuntimeException(RuntimeException ex){
        log.error("RuntimeException:{}",ex);
        if(ex.getCause() instanceof BaseServiceException){
            BaseServiceException bse = (BaseServiceException) ex.getCause();
            return new State(bse.getErrorCode(), bse.getMessage());
        }
        if(ex instanceof BadSqlGrammarException){
            return new State(HttpStatus.INTERNAL_SERVER_ERROR.value() * 10, "SQL语句语法错误");
        } else if (ex instanceof DataIntegrityViolationException){
            return new State(HttpStatus.BAD_REQUEST.value() * 10, "数据违反数据库完整性");
        } else if (ex instanceof MethodArgumentTypeMismatchException){
            return new State(HttpStatus.BAD_REQUEST.value() * 10, "参数类型错误");
        }
        return new State(HttpStatus.INTERNAL_SERVER_ERROR.value() * 10, "未知异常");
    }
}


